﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using NET.Tools.WPF;
using Puzzler.GUI.Exceptions;
using Puzzler.GUI.Windows.Wizard;
using Puzzler.Plugin.Interface;
using Puzzler.XML;

namespace Puzzler.GUI
{
    internal static class WizardBuilder
    {
        public static WizardWindow Build(XWizard wizard)
        {
            PuzzleData data = new PuzzleData();
            WizardWindow win = new WizardWindow(data);

            //Build the always shown first page
            BuildFirstPage(win, data);

            if (wizard.Pages.GridPage != null)
            {
                BuildGridPage(win, data, wizard.Pages.GridPage.title);
            }

            if (wizard.Pages.OtherPages != null)
            {
                BuildOtherPages(wizard, win, data);
            }

            win.PageUpdate();
            return win;
        }

        private static void BuildOtherPages(XWizard wizard, WizardWindow win, PuzzleData data)
        {
            foreach (object item in wizard.Pages.OtherPages.Items)
            {
                if (item is XSimplePage)
                {
                    XSimplePage xPage = item as XSimplePage;
                    IDictionary<String, String> pageData = new Dictionary<string, string>();

                    StackPanel panel = new StackPanel
                        {
                            Orientation = Orientation.Vertical,
                            Tag =
                                new PanelInfo(xPage.cancelactivated, xPage.finishactivated, xPage.cangoback,
                                              xPage.title)
                        };

                    FillContainer(xPage, panel.Children, pageData);

                    data.ValueMap.Add(xPage.key, pageData);
                    win.pnlPage.Children.Add(panel);
                }
                else if (item is XCustomPage)
                {
                    XCustomPage xPage = item as XCustomPage;
                    IDictionary<String, String> pageData = new Dictionary<string, string>();

                    Type type = Type.GetType(xPage.type);
                    if (type == null)
                        throw new ArgumentException("Cannot find type: " + xPage.type);
                    FrameworkElement visual = (FrameworkElement) Activator.CreateInstance(type, pageData);
                    visual.Tag = new PanelInfo(true, false, true, xPage.title);

                    data.ValueMap.Add(xPage.key, pageData);
                    win.pnlPage.Children.Add(visual);
                }
                else
                    throw new NotImplementedException(item.GetType().ToString());
            }
        }

        private static void FillContainer(XContainer container, UIElementCollection visual, IDictionary<string, string> data)
        {
            foreach (var item in container.Items)
            {
                if (item is XLabel)
                {
                    TextBlock lbl = new TextBlock {Text = (item as XLabel).text, TextWrapping = TextWrapping.Wrap};
                    visual.Add(lbl);
                }
                else if (item is XTextBox)
                {
                    XTextBox xTextBox = item as XTextBox;

                    TextBlock lbl = new TextBlock {Text = xTextBox.text};
                    visual.Add(lbl);

                    TextBox txt = new TextBox {Text = xTextBox.content};
                    visual.Add(txt);

                    txt.TextChanged += (s, e) => { data[xTextBox.key] = txt.Text; };
                    data.Add(xTextBox.key, xTextBox.content);//Initial value
                }
                else if (item is XCheckBox)
                {
                    var xCheckBox = (item as XCheckBox);

                    CheckBox ckb = new CheckBox {Content = xCheckBox.text, IsChecked = xCheckBox.@checked};
                    visual.Add(ckb);

                    ckb.Unchecked += (s, e) => { data[xCheckBox.key] = "false"; };
                    ckb.Checked += (s, e) => { data[xCheckBox.key] = "true"; };
                    data.Add(xCheckBox.key, xCheckBox.@checked ? "true" : "false");
                }
                else if (item is XRadioButton)
                {
                    var xRadioButton = (item as XRadioButton);

                    RadioButton rb = new RadioButton {Content = xRadioButton.text, IsChecked = xRadioButton.@checked};
                    visual.Add(rb);

                    rb.Unchecked += (s, e) => { data[xRadioButton.key] = "false"; };
                    rb.Checked += (s, e) => { data[xRadioButton.key] = "true"; };
                    data.Add(xRadioButton.key, xRadioButton.@checked ? "true" : "false");
                }
                else if (item is XGroupBox)
                {
                    var xGroupBox = (item as XGroupBox);

                    GroupBox groupBox = new GroupBox {Header = xGroupBox.title};

                    StackPanel pnl = new StackPanel();
                    FillContainer(item as XContainer, pnl.Children, data);
                    groupBox.Content = pnl;

                    visual.Add(groupBox);
                }
                else if (item is XColorChooser)
                {
                    var xColorChooser = (item as XColorChooser);
                    if (!xColorChooser.color.StartsWith("#"))
                        throw new PuzzlerWizardXMLException("Cannot read xml: Color starts not with '#'!");

                    TextBlock lbl = new TextBlock { Text = xColorChooser.text };
                    visual.Add(lbl);

                    ColorSlider slider = new ColorSlider
                        {
                            Color = (Color) ColorConverter.ConvertFromString(xColorChooser.color)
                        };
                    visual.Add(slider);

                    slider.ColorChanged += (s, e) => { data[xColorChooser.key] = slider.Color.ToString(); };
                    data.Add(xColorChooser.key, xColorChooser.color);
                }
                else if (item is XEmpty)
                {
                    var xEmpty = (item as XEmpty);

                    Border border = new Border {MinHeight = xEmpty.height, MaxHeight = xEmpty.height};

                    visual.Add(border);
                }
                else
                    throw new NotImplementedException(item.GetType().ToString());
            }
        }

        private static void BuildFirstPage(WizardWindow win, PuzzleData data)
        {
            StackPanel panel = new StackPanel();
            panel.Orientation = Orientation.Vertical;
            panel.Tag = new PanelInfo(true, false, false, "Input");
            
            TextBlock lbl1 = new TextBlock();
            lbl1.Text = Resources.GetString("wizard.welcome", CultureInfo.CurrentUICulture);
            lbl1.TextWrapping = TextWrapping.Wrap;
            lbl1.Padding = new Thickness(15);
            panel.Children.Add(lbl1);

            TextBlock lbl2 = new TextBlock();
            lbl2.Text = Resources.GetString("wizard.caption.box", CultureInfo.CurrentUICulture);
            panel.Children.Add(lbl2);

            TextBox txt = new TextBox();
            txt.Text = "Unknown";
            txt.TextChanged += (s, e) => data.Caption = txt.Text;
            data.Caption = "Unknown";
            panel.Children.Add(txt);

            win.pnlPage.Children.Add(panel);
        }

        private static void BuildGridPage(WizardWindow win, PuzzleData data, String title)
        {
            data.GridRects = new List<Rect>();

            WizardGridPage gridPage = new WizardGridPage(data.GridRects);
            gridPage.Tag = new PanelInfo(true, false, true, title);
            win.pnlPage.Children.Add(gridPage);
        }
    }
}
